home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / MATCH.C < prev    next >
C/C++ Source or Header  |  1993-05-20  |  8KB  |  362 lines

  1. #include "jam.h"
  2.   /*
  3.    * Name:    MicroEMACS
  4.    *        Limited parenthesis matching routines
  5.    *
  6.    * The hacks in this file implement automatic matching
  7.    * of (), [], {}, and other characters.     It would be
  8.    * better to have a full-blown syntax table, but there's
  9.    * enough overhead in the editor as it is.
  10.    *
  11.    * Since I often edit Scribe code, I've made it possible to
  12.    * blink arbitrary characters -- just bind delimiter characters
  13.    * to "blink-matching-paren-hack"
  14.    */
  15. #include    "def.h"
  16. #include    "key.h"
  17.   
  18. #ifndef WINDOWED
  19. # include "string.h"
  20. #endif
  21.  
  22. static int  rn_(balance,(KCHAR kchar, int flag, int dir)); /* new params, jam */
  23. static VOID rn_(displaymatch,(LINE *lp, int c, int show, int go));  /* JAM */
  24.  
  25. static BOOL findonly = FALSE;
  26. static LINE *finddotp;
  27. static int finddoto;
  28.  
  29. /* Balance table. When balance() encounters a character
  30.  * that is to be matched, it first searches this table
  31.  * for a balancing left-side character.     If the character
  32.  * is not in the table, the character is balanced by itself.
  33.  * This is to allow delimiters in Scribe documents to be matched.
  34.  */
  35.  
  36. static struct balance {
  37.   char left, right;
  38. } bal[] = {
  39.   { '(', ')' },
  40.   { '[', ']' },
  41.   { '{', '}' },
  42.   { '<', '>' },
  43.   { '\0','\0'}
  44. };
  45. static struct balance2 {
  46.   char *left, *right;
  47. } bal2[] = {
  48.   { "/*", "*/"},
  49.   { (char *)0, (char *)0}
  50. };
  51.  
  52. /* find the char which matches this char in parent line
  53. */
  54. void locatematch(parent, parentdoto, dotp, doto)
  55. LINE *parent;
  56. int parentdoto;
  57. LINE **dotp;
  58. int *doto;
  59. {
  60.   LINE *sdotp = curwp->w_dotp;
  61.   int sdoto = curwp->w_doto;
  62.  
  63.   *dotp = finddotp = (LINE *)0;
  64.   findonly = TRUE;
  65.   curwp->w_dotp = parent; 
  66.   curwp->w_doto = parentdoto;
  67.   balance(lgetc(parent, parentdoto), 0, 1);
  68.   findonly = FALSE;
  69.   if (finddotp)
  70.     {
  71.       *dotp = finddotp;
  72.       *doto = finddoto;
  73.     }
  74.   curwp->w_dotp = sdotp;
  75.   curwp->w_doto = sdoto;
  76. }
  77. /*
  78.  * Self-insert character, then show matching character,
  79.  * if any.  Bound to "blink-matching-paren-command".
  80.  */
  81. showmatch(f, n)
  82. int f, n;
  83. {
  84.   register int  i, s;
  85.   
  86.   if (f & FFRAND) 
  87.     return FALSE;
  88.   for (i = 0; i < n; i++) 
  89.     {
  90.       /* insert the char
  91.       */
  92.       if ((s = selfinsert(FFRAND, 1)) != TRUE)
  93.          return s;
  94.       if (isCindent() && (key.k_chars[key.k_count-1] == '}'))
  95.         alignindent(0, 1);    /* self align hack */
  96.  
  97.       /* show the match
  98.       */
  99.       if (balance(0, 0, 0) != TRUE) /* unbalanced -- warn user */
  100.          ttbeep();
  101.     }
  102.   return TRUE;
  103. }
  104.  
  105. showthematch(f, n)
  106. int f, n;
  107. {
  108.   register LINE    *clp = curwp->w_dotp;
  109.   register int    cbo = curwp->w_doto;
  110.  
  111.   return balance(lgetc(clp,cbo), 0, 0);
  112. }
  113. gotomatch(f, n)
  114. int f, n;
  115. {
  116.   register LINE    *clp = curwp->w_dotp;
  117.   register int    cbo = curwp->w_doto;
  118.  
  119.   return balance(lgetc(clp, cbo), 1, 0);
  120. }
  121.  
  122. /*
  123.  * Search for and display a matching character.
  124.  *
  125.  * This routine does the real work of searching backward
  126.  * for a balancing character.  If such a balancing character
  127.  * is found, it uses displaymatch() to display the match.
  128.  */
  129.  
  130. static balance(kchar, stay, defaultdir)
  131. KCHAR kchar;
  132. int stay;
  133. int defaultdir;
  134. {
  135.   register LINE    *clp;
  136.   register int    cbo;
  137.   int    c;
  138.   int    i;
  139.   int    rbal, lbal;
  140.   int    depth;
  141.   int     dir = -1;      /* normally look backward JAM */
  142.   int     found = FALSE; /* JAM */ 
  143.   
  144.   if (kchar)
  145.     rbal = kchar;
  146.   else
  147.     rbal = key.k_chars[key.k_count-1];
  148.   
  149.   /* See if there is a matching character -- default to the same 
  150.   */
  151.   lbal = rbal;
  152.   for (i = 0; bal[i].right != '\0'; i++)
  153.     if (bal[i].right == (char)rbal) 
  154.       {
  155.     lbal = bal[i].left;
  156.     found = TRUE;
  157.     break;
  158.       }
  159.  
  160.   /* special case of match either direction..
  161.    */
  162.   if (kchar && !found)           /* didn't fin match in table, reverse */
  163.     {                            /* and try again */
  164.       for (i = 0; bal[i].left != '\0'; i++)
  165.     if (bal[i].left == (char)rbal) 
  166.       {
  167.         lbal = bal[i].right;
  168.         dir = 1;       /* going forward now */
  169.         found = TRUE;
  170.         break;
  171.       }
  172.     }
  173.  
  174.   /* control search direction 
  175.   */
  176.   if (defaultdir)
  177.     dir = defaultdir;
  178.   
  179.   /* Move behind the inserted character. We are always guaranteed    
  180.    * that there is at least one character on the line, since one was 
  181.    * just self-inserted by blinkparen.                     
  182.    */
  183.   
  184.   clp = curwp->w_dotp;
  185.   cbo = curwp->w_doto - (kchar ? 0 : 1); /* param/behavior change JAM */
  186.   depth = 0;                     /* init nesting depth */
  187.   
  188.   for (;;) 
  189.     {
  190.     if ((cbo == 0) || (cbo == llength(clp)))
  191.       {
  192.     if ((cbo == 0) && (llength(clp) > 0) && (dir > 0)) 
  193.       ;                         /* front going ->, ok */    
  194.     else if ((cbo > 0) && (cbo == llength(clp)) && (dir < 0)) 
  195.       ;                        /* end going <- ok */
  196.     else
  197.       {    
  198.         clp = (dir > 0 ? lforw(clp) : lback(clp));
  199.         if (!clp || (clp == curbp->b_linep))
  200.           return (FALSE);
  201.         cbo = (dir > 0 ? -1 : llength(clp)+1);
  202.       }
  203.       }
  204.     cbo += dir;
  205.     if (cbo == llength(clp))    /* end of line        */
  206.       c = '\n';
  207.     else
  208.       c = lgetc(clp,cbo);            /* somewhere in middle    */
  209.  
  210.     /* Check for a matching character.  If still in a nested */
  211.     /* level, pop out of it and continue search.  This check */
  212.     /* is done before the nesting check so single-character     */
  213.     /* matches will work too.                 */
  214.     if (c == lbal) 
  215.       {
  216.     if (depth == 0) 
  217.       {
  218.             if (findonly)
  219.               {
  220.                 finddotp = clp;
  221.                 finddoto = cbo;
  222.                 return (TRUE);
  223.                }
  224.         displaymatch(clp, cbo, kchar != 0, stay);
  225.         return (TRUE);
  226.       }
  227.       else
  228.     depth--;
  229.     }
  230.     /* Check for another level of nesting.    */
  231.     if (c == rbal)
  232.       depth++;
  233.   }
  234.   /*NOTREACHED*/
  235. }
  236.  
  237.  
  238. /*
  239.  * Display matching character.
  240.  * Matching characters that are not in the current window
  241.  * are displayed in the echo line. If in the current
  242.  * window, move dot to the matching character,
  243.  * sit there a while, then move back.
  244.  *
  245.  * I bashed this big time to support finding a match in 
  246.  * either direction (JAM)
  247.  */
  248. static VOID displaymatch(clp, cbo, show, go)
  249. register LINE *clp;
  250. register int  cbo;
  251. register int show, go;
  252. {
  253.   register LINE    *tlp;
  254.   register int    tbo;
  255.   register int    cp;
  256.   register int    bufo;
  257.   register int    c;
  258.   int        inwindow;
  259.   char        buf[NLINE];
  260.   
  261.   /* Figure out if matching char is in current window by    */
  262.   /* searching from the top of the window to dot.        */
  263.   
  264.   inwindow = FALSE;
  265.   for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); 
  266.        tlp = lforw(tlp))
  267.     if (tlp == clp)
  268.       inwindow = TRUE;
  269.   
  270.   if ((inwindow == TRUE) || show)  /* if force, move anyway */
  271.     {
  272.       tlp = curwp->w_dotp;      /* save current position */
  273.       tbo = curwp->w_doto;
  274.       
  275.       curwp->w_dotp  = clp;      /* move to new position */
  276.       curwp->w_doto  = cbo;
  277.       curwp->w_flag |= WFMOVE;
  278.       
  279.       update();          /* show match */
  280.  
  281. #ifdef WINDOWED
  282.       {
  283.         BOOL wasVis = IsCaretVis();
  284.  
  285.         /* Due to windows issues around cursor, it    
  286.          * is erased while processing an event. Special case
  287.          * draw/erase cursor here for feedback.
  288.          */
  289.         if (go)
  290.       return;               /* means move and stay */
  291.         SetCaretVis(TRUE);
  292.         ttflush(TRUE);
  293.         sleep(1);        /* wait a bit */
  294.         if (!wasVis)
  295.           SetCaretVis(FALSE);
  296.         ttflush(TRUE);
  297.       }
  298. #else
  299.       sleep(1);        /* wait a bit */
  300. #endif
  301.       curwp->w_dotp    = tlp;    /* return to old position */
  302.       curwp->w_doto    = tbo;
  303.       curwp->w_flag  |= WFMOVE;
  304.       update();
  305.     }
  306.   else 
  307.     {    /* match not in this window so display line in echo area */
  308.       bufo = 0;
  309.       for (cp = 0; cp < llength(clp); cp++)  /* expand tabs    */
  310.     {
  311.       c = lgetc(clp,cp);
  312.       if (c != '\t'
  313. #ifdef    NOTAB
  314.           || (curbp->b_flag & BFNOTAB)
  315. #endif
  316.           )
  317.         if(ISCTRL(c)) 
  318.          {
  319.            buf[bufo++] = '^';
  320.            buf[bufo++] =(char)(CCHR(c));
  321.          } 
  322.         else 
  323.         buf[bufo++] = (char)c;
  324.       else
  325.         do {
  326.           buf[bufo++] = ' ';
  327.         } while (bufo & 7);
  328.     }
  329.       buf[bufo++] = '\0';
  330.       ewprintf("Matches %s",buf);
  331.     }
  332. }
  333. char *matchstr(s)
  334. char *s;
  335. {
  336.   register int i;
  337.  
  338.   for (i = 0; bal2[i].right; i++)
  339.     {
  340.       if (strncmp(bal2[i].left, s, strlen(s)) == 0)
  341.         return(bal2[i].right);
  342.       else if (strncmp(bal2[i].right, s, strlen(s)) == 0)
  343.         return(bal2[i].left);
  344.     }
  345.   return((char *)0);
  346. }
  347. char matchchar(c)
  348. char c;
  349. {
  350.   register int i;
  351.  
  352.   for (i = 0; bal[i].right != '\0'; i++)
  353.     {
  354.       if (bal[i].left == c)
  355.         return(bal[i].right);
  356.       else if (bal[i].right == c)
  357.         return(bal[i].left);
  358.     }
  359.   return(0);
  360. }
  361.  
  362.